﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace DataLayer.Generic
{
    [DefaultEvent("Selecting"), ToolboxBitmap(typeof(ObjectDataSource)), Designer("System.Web.UI.Design.WebControls.ObjectDataSourceDesigner, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), PersistChildren(false), DisplayName("ObjectDataSource_DisplayName"), DefaultProperty("TypeName"), Description("ObjectDataSource_Description"), ParseChildren(true), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class GenericObjectDataSource : ObjectDataSource
    {
        const BindingFlags NeedlesslyPrivate = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;

        static MethodInfo s_InvalidateCacheEntry;
        static MethodInfo s_GetCache;
        static MethodInfo s_GetCacheEnabled;
        static FieldInfo s_View;

        static GenericObjectDataSource()
        {
            s_InvalidateCacheEntry = typeof(ObjectDataSource).GetMethod("InvalidateCacheEntry", NeedlesslyPrivate, null, new Type[0], null);
            PropertyInfo cache = typeof(ObjectDataSource).GetProperty("Cache", NeedlesslyPrivate);
            s_GetCache = cache.GetGetMethod(true);
            PropertyInfo cacheEnabled = cache.PropertyType.GetProperty("Enabled", NeedlesslyPrivate);
            s_GetCacheEnabled = cacheEnabled.GetGetMethod(true);
            s_View = typeof(ObjectDataSource).GetField("_view", NeedlesslyPrivate);
        }

        public GenericObjectDataSource()
        {
            // force creation!
            this.GetView();

            #region Generic Repository Defaults
            SelectMethod = "SelectAll";
            InsertMethod = "Insert";
            DeleteMethod = "Delete";
            UpdateMethod = "Update";
            OldValuesParameterFormatString = "original_{0}";
            SelectCountMethod = "Count";
            StartRowIndexParameterName = "startRowIndex";
            MaximumRowsParameterName = "maximumRows";

            Parameter deleteParameterEntity = new Parameter("entity", TypeCode.Object);
            Parameter deleteParameterSubmitChanges = new Parameter("submitChanges", TypeCode.Boolean, "true");
            DeleteParameters.Add(deleteParameterEntity);
            DeleteParameters.Add(deleteParameterSubmitChanges);

            Parameter updateParameterEntity = new Parameter("entity", TypeCode.Object);
            Parameter updateParameterSubmitChanges = new Parameter("submitChanges", TypeCode.Boolean, "true");
            UpdateParameters.Add(updateParameterEntity);
            UpdateParameters.Add(updateParameterSubmitChanges);
            #endregion
        }

        public GenericObjectDataSource(string typeName, string selectMethod)
            : base(typeName, selectMethod)
        {
            // force creation!
            this.GetView();

            #region Generic Repository Defaults
            SelectMethod = "SelectAll";
            InsertMethod = "Insert";
            DeleteMethod = "Delete";
            UpdateMethod = "Update";
            OldValuesParameterFormatString = "original_{0}";
            SelectCountMethod = "Count";
            StartRowIndexParameterName = "startRowIndex";
            MaximumRowsParameterName = "maximumRows";

            Parameter deleteParameterEntity = new Parameter("entity", TypeCode.Object);
            Parameter deleteParameterSubmitChanges = new Parameter("submitChanges", TypeCode.Boolean, "true");
            DeleteParameters.Add(deleteParameterEntity);
            DeleteParameters.Add(deleteParameterSubmitChanges);

            Parameter updateParameterEntity = new Parameter("entity", TypeCode.Object);
            Parameter updateParameterSubmitChanges = new Parameter("submitChanges", TypeCode.Boolean, "true");
            UpdateParameters.Add(updateParameterEntity);
            UpdateParameters.Add(updateParameterSubmitChanges);
            #endregion
        }

        protected virtual ObjectDataSourceView GetView()
        {
            ObjectDataSourceView view = (ObjectDataSourceView)s_View.GetValue(this);

            if (view == null)
            {
                view = new GenericObjectDataSourceView(this, "DefaultView", this.Context);
                s_View.SetValue(this, view);

                if (base.IsTrackingViewState)
                {
                    ((IStateManager)view).TrackViewState();
                }
            }

            return view;
        }

        protected override DataSourceView GetView(string viewName)
        {
            if (viewName == null || (viewName.Length != 0 && !string.Equals(viewName, "DefaultView", StringComparison.OrdinalIgnoreCase)))
            {
                throw new ArgumentException(ExposedSR.GetString(ExposedSR.InvalidViewName, new object[] { this.ID, "DefaultView" }), "viewName");
            }

            return this.GetView();
        }

        internal void InvalidateCache()
        {
            object cache = s_GetCache.Invoke(this, null);
            object cacheEnabled = s_GetCacheEnabled.Invoke(cache, null);

            if ((bool)cacheEnabled)
            {
                s_InvalidateCacheEntry.Invoke(this, null);
            }
        }
    }
}
